import java.util.concurrent.Semaphore;


public class Receiver extends Thread {
	private int[] networkCode;
	private int[] cellCode;
	private int[] spreadCode;
	private int[] goldCode;
	private Semaphore sem;
	private int[] mess;
	private int[][] receivedSignal;
	private int[][] receivedSignalDescrambled;
	private int[] signalToDespread;
	private int nbFrames = 0;
	private int lengthChips;
	private int lengthMessage;
	private int[] originalMess;
	private BaseStation bs; 
	private UMTS frame;
	private int id;
	
	public void setOriginalMess(int[] originalMess) {
		this.originalMess = new int[originalMess.length];
		for(int i=0;i<originalMess.length;i++){
			this.originalMess[i] = originalMess[i];
		}
		
	}

	public Receiver(int id, int[] networkCode, int[] cellCode, int[] spreadCode, int[]goldCode, int lengthChips, int lengthMessage, int nbReceivers, BaseStation bs, UMTS frame){
		this.id = id;
		this.frame = frame;
		this.networkCode = networkCode;
		this.cellCode = cellCode;
		this.spreadCode = spreadCode;
		this.goldCode = goldCode;
		this.lengthChips = lengthChips;
		this.lengthMessage = lengthMessage;
		this.sem = new Semaphore(0, true);
		this.bs = bs;
	}
	
	public void run(){
		try {
			sem.acquire();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		//System.out.println("run receiver");
		nbFrames = receivedSignal.length;
		int nbFrame = 0;
		boolean messOk = false;
		while(true){
			messOk = true;
			if(nbFrame < nbFrames){
				try {
					sem.acquire();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}		
				descrambling();
				nbFrame++;
			}
			else{
				nbFrame = 0;
				signalToDespread = new int[nbFrames * lengthChips] ;
				for (int m=0; m < nbFrames; m++){	
					for (int i=0; i< receivedSignalDescrambled[m].length ; i++){
						signalToDespread[(m*lengthChips)+i] = receivedSignalDescrambled[m][i];
					}
					
				}
				despreading();
				
				String stringMess = "";
				
				for(int j=0; j<lengthMessage; j++){
					stringMess += mess[j];
				}
				
				for(int y = 0;y<originalMess.length;y++){
					if(!(mess[y] == originalMess[y])){
						messOk = false;
					}
				}
				
				if(messOk){
					frame.print("\t\tUser "+id+" : "+ stringMess);
					bs.setReceiversOk(id, true);
					bs.releaseSemOk(id);
					break;
				}
				else{
					frame.print("User "+id+" : Error during the transmission... -- Message Received : " + stringMess);
					bs.setReceiversError(id, true);
					bs.releaseSemOk(id);
				}
			}
		}
	}
	
	public void despreading(){
		int[] tempSignal = new int[signalToDespread.length];
		for(int i=0; i<signalToDespread.length;i++){
			tempSignal[i] = signalToDespread[i] * spreadCode[i%spreadCode.length];
		}
		
		mess = new int[lengthMessage];
		
		int j=0;	
		
		int init = 0;
		if(tempSignal.length / spreadCode.length > lengthMessage){
			init = lengthMessage*spreadCode.length;
		}
		for(int i=init; i<tempSignal.length;i=i+spreadCode.length){
			float temp = 0;
			for(int o=0; o<spreadCode.length; o++){
				temp += tempSignal[i+o];
			}
			
			if(temp / spreadCode.length < 0){
				mess[j] = 0;
			}
			else{
				mess[j] = 1;
			}
			j++;
		}
	}
	
	public void descrambling(){
		int mod = 0;
		int indice = 0;
		
		receivedSignalDescrambled = new int[receivedSignal.length][lengthChips];
		for(int m=0; m<receivedSignal.length;m++){	
			mod = (int) receivedSignal[m].length / goldCode.length;
			for(int i=0;i<receivedSignal[m].length;i++){
				indice = i % mod;
				receivedSignalDescrambled[m][i] = receivedSignal[m][i] * goldCode[indice];
			}
		}
	}

	public void releaseSem(){
		this.sem.release();
	}
	
	public int[] getNetworkCode() {
		return networkCode;
	}

	public void setNetworkCode(int[] networkCode) {
		this.networkCode = networkCode;
	}

	public int[] getCellCode() {
		return cellCode;
	}

	public void setCellCode(int[] cellCode) {
		this.cellCode = cellCode;
	}

	public int[] getSpreadCode() {
		return spreadCode;
	}

	public void setSpreadCode(int[] spreadCode) {
		this.spreadCode = spreadCode;
	}

	public int[][] getReceivedSignal() {
		return receivedSignal;
	}

	public void setReceivedSignal(int[][] receivedSignal) {
		this.receivedSignal = receivedSignal;
	}
	
	
	
	

	public void setNbFrames(int nbFrames) {
		this.nbFrames = nbFrames;
		signalToDespread = new int[nbFrames * lengthChips] ;
	}

	public String toString(){
		String returnString =  "networkCode:"+this.networkCode+" cellCode:"+this.cellCode+" spreadCode:";
		for(int i=0;i<this.spreadCode.length; i++){
			returnString += "\t";
			returnString += this.spreadCode[i];
		}

		returnString += '\n';
		return returnString;
	}
}
